// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == 'object' && typeof module == 'object')
    // CommonJS
    mod(require('../../lib/codemirror'));
  else if (typeof define == 'function' && define.amd)
    // AMD
    define(['../../lib/codemirror'], mod);
  // Plain browser env
  else mod(CodeMirror);
})(function(CodeMirror) {
  'use strict';

  CodeMirror.defineMode('yaml', function() {
    var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
    var keywordRegex = new RegExp('\\b((' + cons.join(')|(') + '))$', 'i');

    return {
      token: function(stream, state) {
        var ch = stream.peek();
        var esc = state.escaped;
        state.escaped = false;
        /* comments */
        if (
          ch == '#' &&
          (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))
        ) {
          stream.skipToEnd();
          return 'comment';
        }

        if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/)) return 'string';

        if (state.literal && stream.indentation() > state.keyCol) {
          stream.skipToEnd();
          return 'string';
        } else if (state.literal) {
          state.literal = false;
        }
        if (stream.sol()) {
          state.keyCol = 0;
          state.pair = false;
          state.pairStart = false;
          /* document start */
          if (stream.match(/---/)) {
            return 'def';
          }
          /* document end */
          if (stream.match(/\.\.\./)) {
            return 'def';
          }
          /* array list item */
          if (stream.match(/\s*-\s+/)) {
            return 'meta';
          }
        }
        /* inline pairs/lists */
        if (stream.match(/^(\{|\}|\[|\])/)) {
          if (ch == '{') state.inlinePairs++;
          else if (ch == '}') state.inlinePairs--;
          else if (ch == '[') state.inlineList++;
          else state.inlineList--;
          return 'meta';
        }

        /* list seperator */
        if (state.inlineList > 0 && !esc && ch == ',') {
          stream.next();
          return 'meta';
        }
        /* pairs seperator */
        if (state.inlinePairs > 0 && !esc && ch == ',') {
          state.keyCol = 0;
          state.pair = false;
          state.pairStart = false;
          stream.next();
          return 'meta';
        }

        /* start of value of a pair */
        if (state.pairStart) {
          /* block literals */
          if (stream.match(/^\s*(\||\>)\s*/)) {
            state.literal = true;
            return 'meta';
          }
          /* references */
          if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) {
            return 'variable-2';
          }
          /* numbers */
          if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) {
            return 'number';
          }
          if (
            state.inlinePairs > 0 &&
            stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)
          ) {
            return 'number';
          }
          /* keywords */
          if (stream.match(keywordRegex)) {
            return 'keyword';
          }
        }

        /* pairs (associative arrays) -> key */
        if (
          !state.pair &&
          stream.match(
            /^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/,
          )
        ) {
          state.pair = true;
          state.keyCol = stream.indentation();
          return 'atom';
        }
        if (state.pair && stream.match(/^:\s*/)) {
          state.pairStart = true;
          return 'meta';
        }

        /* nothing found, continue */
        state.pairStart = false;
        state.escaped = ch == '\\';
        stream.next();
        return null;
      },
      startState: function() {
        return {
          pair: false,
          pairStart: false,
          keyCol: 0,
          inlinePairs: 0,
          inlineList: 0,
          literal: false,
          escaped: false,
        };
      },
    };
  });

  CodeMirror.defineMIME('text/x-yaml', 'yaml');
  CodeMirror.defineMIME('text/yaml', 'yaml');
});
